/**
 * @class Spark.DataSet
 * @extends Ext.util.Observable
 * <p>DataSet是一个数据源，也是一个数据集合，它封装了所有数据的操作，校验，提交等操作.
 * @author niujiaqing
 * @constructor
 * @param {Object} config 配置对象. 
 * 
 */
$S.AUTO_ID = 1000;
$S.DataSet = Ext.extend(Ext.util.Observable,{
	constructor: function(cfg) {
		$S.DataSet.superclass.constructor.call(this);
		cfg = cfg || {};
		if(cfg.listeners){
            this.on(cfg.listeners);
        }
        
        this.id = cfg.id || Ext.id();
        $S.CmpManager.put(this.id,this);
        
        this.fields = {};
        //submit parameter
    	this.sp = {};
    	//query  parameter
    	this.qp = {};
    	
    	this.selected = [];
        
        this.sortModel = cfg.sortModel||'local';
        this.defaultSortField = cfg.defaultSortField;
        this.defaultSortType = cfg.defaultSortType;
        if(cfg.defaultSortField) this.setQueryParameter('ORDER_FIELD', cfg.defaultSortField);
        if(cfg.defaultSortType) this.setQueryParameter('ORDER_TYPE', cfg.defaultSortType);
        
    	//page size
    	this.psize = cfg.psize || 10;
    	
    	//submit url
    	this.surl = cfg.surl || '';
    	//query url
    	this.qurl = cfg.qurl || '';
    	
    	//selectable
    	this.sb = cfg.sb||false;
    	//selection model
    	this.sm = cfg.sm||'multiple'; 
    	//selectfunction
    	this.sft = cfg.sft;
    	this.checkDirty = cfg.checkDirty;
        
    	//bind target
    	if(cfg.bt)this.bt = cfg.bt;
    	
    	//bind name
    	if(cfg.bn)this.bn = cfg.bn;
        
        this.loading = false;
    	//loadingTip
        this.loadingTip = cfg.loadingTip;
        this.successTip = cfg.successTip;
        this.lock = cfg.lock;
        
    	this.clear();
        
        if(this.bt&&this.bn) this.bind($(this.bt),this.bn);
    	this.qds = Ext.isEmpty(cfg.qds) ? null : $(cfg.qds);
    	if(this.qds != null && this.qds.current() == null) this.qds.create();
    	
    	this.initEvents();
    	if(cfg.fields) this.initFields(cfg.fields)
    	if(cfg.datas && cfg.datas.length != 0) {
           this.loadData(cfg.datas);
           this.locate(this.currentIndex,true);
    	}else if(cfg.notFoundMessage){
            var cb = $S.getFunction(cfg.notFoundCallback)
            $S.showInfoMessage('提示', cfg.notFoundMessage, cb);
            return;
        }
    	//auto query
    	if(cfg.aq === true) {
            var sf = this;
            $S.onReady(function(){
               sf.query(); 
            });
    	}
    	//auto create
    	if(cfg.ac == true) {
            if(this.datas.length == 0)
            this.create();
    	}
    },
    destroy : function(){
    	if(this.bt && this.bn){
            var bd = $S.CmpManager.get(this.bt)
            if(bd) bd.unBind();
    	}
    	$S.CmpManager.remove(this.id);
    },
    reConfig : function(config){
    	this.clear();
    	Ext.apply(this, config);
    },
    /**
     * 取消绑定.
     */
    unBind : function(){
    	var name = this.bn;
        var ds = this.fields[name].pro['dataset'];
        if(ds)
        ds.processBindDataSetListener(this,'un');
        delete this.fields[name];
    },
    processBindDataSetListener : function(ds,ou){
        var bdp = this.onDataSetModify;
        this[ou]('add', bdp, this);
        this[ou]('remove', bdp, this);
        this[ou]('update', bdp, this);
        this[ou]('clear', bdp, this);
        this[ou]('indexchange', bdp, this);
        this[ou]('load', this.onDataSetLoad, this);
        this[ou]('reject', bdp, this);
        ds[ou]('indexchange',this.onDataSetIndexChange, this);
        ds[ou]('load',this.onBindDataSetLoad, this);
        ds[ou]('remove',this.onBindDataSetLoad, this);
        ds[ou]('clear',this.removeAll, this);
    },
    /**
     * 将当前DS绑定到某个DS的Field上.
     * @param {Spark.DataSet} dataSet 绑定的DataSet.
     * @param {String} name Field的name. 
     * 
     */
    bind : function(ds, name){
        if(ds.fields[name]) {
            return;
        }
        this.processBindDataSetListener(ds,'un');
        this.processBindDataSetListener(ds,'on');
        var field = new $S.Record.Field({
            name:name,
            type:'dataset',
            dataset:this
        });
        ds.fields[name] = field;
    },
    /**
     * 是否存在修改的record
     * @return {Boolean}
     */
    isDirty : function(){
        var dirty = false;
        if(this.checkDirty)
        for(var i = 0,len = this.datas.length; i < len; i++){
            if(dirty)break;
            var r = this.datas[i];
            if(r.isDirty){
                dirty = true
            }else {
                for(var k in this.fields){
                    var field = this.fields[k];
                    if(field.type == 'dataset'){
                        var ds = field.pro['dataset'];
                        if(r && r.data[field.name]){
                            ds.reConfig(r.data[field.name]);
                            dirty = ds.isDirty();
                            if(dirty)break;
                        }
                    }
                }
            }
        }
        
        return dirty;
    },
    onBindDataSetLoad : function(ds,options){
        if(ds.getAll().length == 0) this.removeAll();
    },
    onDataSetIndexChange : function(ds, record){
    	if(!record.get(this.bn) && record.isNew != true){
    		this.qp = {};
            Ext.apply(this.qp,record.data);
            this.query(1,{record:record});
    	} 	
    },
    onDataSetModify : function(){
    	var bt = $S.CmpManager.get(this.bt);
    	if(bt){
            this.refreshBindDataSet(bt.current(),this.getConfig())
    	}
    },
    onDataSetLoad : function(ds,options){
    	var record;
    	if(options){
    		record = options.opts.record;
    	}else{
    		var bt = $S.CmpManager.get(this.bt);
    		if(bt) record = bt.current();    		
    	}
    	if(record)
    	this.refreshBindDataSet(record,ds.getConfig())
    },
   	refreshBindDataSet: function(record,config){
    	if(!record)return;
    	record.set(this.bn,config,true)
    },
    clear : function(){
    	this.datas = [];
        this.fields = {};
    	this.selected = [];
    	this.gotoPage = 1;
    	this.currentPage = 1;
    	this.currentIndex = 1;
    	this.totalCount = 0;
    	this.totalPage = 0;
    	this.isValid = true;
    },
    getConfig : function(){
    	var c = {};
    	c.xtype = 'dataset';
        c.fields = this.fields;
    	c.datas = this.datas;
    	c.selected = this.selected;
    	c.isValid = this.isValid;
    	c.gotoPage = this.gotoPage;
    	c.currentPage = this.currentPage;
    	c.currentIndex = this.currentIndex;
    	c.totalCount = this.totalCount;
    	c.totalPage = this.totalPage;
    	return c;
    },
    initEvents : function(){
    	this.addEvents( 
    	    /**
             * @event add
             * 数据增加事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Spark.Record} record 增加的record.
             * @param {Number} index 指针.
             */
            'add',
            /**
             * @event ajaxfailed
             * ajax调用失败.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             */
            'ajaxfailed',
    	    /**
             * @event beforecreate
             * 数据创建前事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @return {boolean} result 返回结果.如果为false则中断create,默认返回true
             */
    		'beforecreate',
	        /**
             * @event beforeremove
             * 数据删除前.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @return {boolean} result 返回结果.如果为false则中断remove,默认返回true
             */
            'beforeremove',
	        /**
             * @event beforeload
             * 准备加载数据事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Array} datas record集合.
             */ 
	        'beforeload',
	        /**
             * @event beforesubmit
             * 数据提交前事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @return {boolean} result 返回结果.如果为false则中断submit,默认返回true
             */
            'beforesubmit',
            /**
             * @event clear
             * 清除数据事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             */
            'clear',
	        /**
             * @event fieldchange
             * field配置改变事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Spark.Record} record 当前的record.
             * @param {Spark.Record.Field} field Field配置对象.
             * @param {String} type 类型.
             * @param {Object} value 值.
             */
            'fieldchange',
            /**
             * @event indexchange
             * DataSet当前指针改变事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Spark.Record} record 当前record.
             */ 
            'indexchange',
            /**
             * @event load
             * 加载数据事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             */ 
	        'load',
	        /**
             * @event loadfailed
             * 加载数据失败.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             */ 
            'loadfailed',
            /**
             * @event query
             * 查询事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             */ 
            'query',
	        /**
             * @event refresh
             * 刷新事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             */ 
	        'refresh',	
	        /**
             * @event remove
             * 数据删除事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Spark.Record} record 删除的record.
             * @param {Number} index 指针.
             */
            'remove',
            /**
             * @event reject
             * 数据重置事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Spark.Record} record 取消选择的record.
             * @param {String} name 重置的field.
             * @param {Object} value 重置的值.
             */
            'reject',
            /**
             * @event select
             * 选择数据事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Spark.Record} record 选择的record.
             */ 
            'select',
            /**
             * @event submit
             * 数据提交事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             */
            'submit',
            /**
             * @event submitsuccess
             * 数据提交成功事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             */
            'submitsuccess',
            /**
             * @event submitfailed
             * 数据提交失败事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             */
            'submitfailed',
	        /**
             * @event update
             * 数据更新事件.
             * "update", this, record, name, value
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Spark.Record} record 更新的record.
             * @param {String} name 更新的field.
             * @param {Object} value 更新的值.
             */
            'update',
	        /**
             * @event select
             * 取消选择数据事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Spark.Record} record 取消选择的record.
             */
	        'unselect',
	        /**
             * @event valid
             * DataSet校验事件.
             * @param {Spark.DataSet} dataSet 当前DataSet.
             * @param {Spark.Record} record 校验的record.
             * @param {String} name 校验的field.
             * @param {Boolean} valid 校验结果. true 校验成功  false 校验失败
             */ 
            'valid'
		);    	
    },
    initFields : function(fields){
    	for(var i = 0, len = fields.length; i < len; i++){
    		var field = new $S.Record.Field(fields[i]);
	        this.fields[field.name] = field;
        }
    },
    /**
     * 获取dataSet级别的Field
     * @param {String} name Field的name. 
     * @return {Spark.Record.Field} field配置对象
     */
    getField : function(name){
    	return this.fields[name];
    },
    clearFilter : function(){
        if(this.backup){
            this.datas = this.backup;
            delete this.backup;
        }
    },
    filter : function(callback, scope){
        this.clearFilter();
        var d = this.backup||this.datas,nd = [];
        this.backup = d;
        Ext.each(d,function(o){
            if(callback.call(scope||this,o)!==false){
                nd.push(o); 
            }
        },this)
        this.datas = nd;
    },
    loadData : function(datas, num, options){  
        this.clearFilter();
        this.datas = [];
        this.selected = [];
        if(num) {
        	this.totalCount = num;
        }else{
        	this.totalCount = datas.length;
        }
    	this.totalPage = (this.psize == -1) ? 1 : Math.ceil(this.totalCount/this.psize)
    	for(var i = 0, len = datas.length; i < len; i++){
    		var data = datas[i].data||datas[i];
    		for(var key in this.fields){
    			var field = this.fields[key];
    			if(field){
                    var val = this.processData(data,key,field);
                    if(val) data[key] = val; 
    			}
    		}
    		var record = new $S.Record(data,datas[i].field);
            record.ds = this;
	        this.datas.push(record);
        }
//        if(this.sortInfo) this.sort();
        
        this.fireEvent("beforeload",this,this.datas);
        var needFire = true;
        if(this.bt && options){
           var cr = $S.CmpManager.get(this.bt).current();
           if(options.opts.record && cr!=options.opts.record){
               this.refreshBindDataSet(options.opts.record,this.getConfig());
               needFire = false;
           }
        }
        if(needFire)
        this.fireEvent("load", this, options);
    },
    sort : function(f, direction){
    	if(this.getAll().length==0)return;
        if(this.sortModel == 'remote'){
            if(direction=='') {
                delete this.qp['ORDER_FIELD'];
                delete this.qp['ORDER_TYPE'];
            }else{
                this.setQueryParameter('ORDER_FIELD', f);
                this.setQueryParameter('ORDER_TYPE', direction);
            }
            this.query();
        }else{
            this.datas.sort(function(a, b){
                var rs = a.get(f) > b.get(f)
                return (direction == 'desc' ? (rs ? -1 : 1) : (rs ? 1 : -1));
            })
            this.fireEvent('refresh',this);
        }
    },
    /**
     * 创建一条记录
     * @param {Object} data 数据对象
     * @return {Spark.Record} record 返回创建的record对象
     */
    create : function(data){
    	if(this.fireEvent("beforecreate", this)){
        	data = data||{}
        	var dd = {};
        	for(var k in this.fields){
        		var field = this.fields[k];
        		var dv = field.getPro('defaultValue');
                if(dv && !data[field.name]){
                    dd[field.name] = dv;
                }
        	}
            for(var k in this.fields){
                var field = this.fields[k];
                 var dv = this.processValueListField(dd,data[field.name],field);
                 if(dv) dd[field.name] = dv;
            }
        	var data = Ext.apply(data||{},dd);
        	var record = new $S.Record(data);
            this.add(record); 
            return record;
    	}
    },
    /**
     * 获取所有新创建的数据. 
     * @return {Array} 所有新创建的records
     */
    getNewRecrods: function(){
        var records = this.getAll();
        var news = [];
       	for(var k = 0,l=records.length;k<l;k++){
			var record = records[k];
			if(record.isNew == true){
				news.push(record);
			}
		}
		return news;
    },
    /**
     * 新增数据. 
     * @param {Spark.Record} record 需要新增的Record对象. 
     */
    add : function(record){
    	record.isNew = true;
        record.ds = this;
        var index = this.datas.length;
        this.datas.add(record);
        var index = (this.currentPage-1)*this.psize + this.datas.length;
        this.currentIndex = index;
        this.fireEvent("add", this, record, index);
        this.locate(index, true);
    },
    /**
     * 获取当前指针的Record. 
     * @return {Spark.Record} 当前指针所处的Record
     */
    current : function(){
    	if(this.datas.length ==0) return null;
    	return this.datas[this.currentIndex - (this.currentPage-1)*this.psize -1];
    },
    /**
     * 插入数据. 
     * @param {Number} index  指定位置. 
     * @param {Array} records 需要新增的Record对象集合.
     */
    insert : function(index, records){
        records = [].concat(records);
        var splice = this.datas.splice(index,this.datas.length);
        for(var i = 0, len = records.length; i < len; i++){
            records[i].ds = this;
            this.datas.add(records[i]);
        }
        this.datas = this.datas.concat(splice);
        this.fireEvent("add", this, records, index);
    },
    /**
     * 移除数据.  
     * @param {Spark.Record} record 需要移除的Record.
     */
    remove : function(record){  
    	if(!record){
    		record = this.current();
    	}
    	if(!record)return;
    	//根据beforeremove的返回值决定是否删除数据
    	if(this.fireEvent("beforeremove", this)){
        	var rs = [].concat(record);
        	var rrs = [];
        	for(var i=0;i<rs.length;i++){
        		var r = rs[i]
        		if(r.isNew){
                    this.removeLocal(r);
        		}else{    		
                    rrs[rrs.length] = r;
        		}
        	}
        	this.removeRemote(rrs);
    	}
    },
    removeRemote: function(rs){    	
    	if(this.surl == '') return;
    	var p = [];
    	for(var k=0;k<rs.length;k++){
    		var r = rs[k]
    		for(var key in this.fields){
                var f = this.fields[key];
                if(f && f.type == 'dataset') delete r.data[key];
            }
        	var d = Ext.apply({}, r.data);
    		d['_id'] = r.id;
    		d['_status'] = 'delete';
            p[k] = Ext.apply(d,this.sp)
    	}
    	if(p.length > 0) {
    		var opts;
    		if(this.bt){
                var bd = $S.CmpManager.get(this.bt);
                opts = {record:bd.current(),dataSet:this};
    		}
	    	$S.request({url:this.surl, para:p, success:this.onRemoveSuccess, error:this.onSubmitError, scope:this, failure:this.onAjaxFailed,opts:opts});
    	}
    
    },
    onRemoveSuccess: function(res,options){
    	if(res.result){
    		var datas = [].concat(res.result);
    		if(this.bt){
                var bd = $S.CmpManager.get(this.bt);
                if(bd.current()==options.opts.record){
                    for(var i=0;i<datas.length;i++){
                        var data = datas[i];
                        this.removeLocal(this.findById(data['_id']),true); 
                    }
                }else{
                    var config = options.opts.record.get(this.bn);
                    var ds = new $S.DataSet({});
                    ds.reConfig(config);
                    for(var i=0;i<datas.length;i++){
                        var data = datas[i];
                        ds.removeLocal(ds.findById(data['_id']),true);
                    }
                    this.refreshBindDataSet(options.opts.record,ds.getConfig())
                    delete ds;
                }
            }else{
                for(var i=0;i<datas.length;i++){
                    var data = datas[i];
                    this.removeLocal(this.findById(data['_id']),true); 
                }
            }
    	}
    },
    removeLocal: function(record,count){
//    	$S.removeInvalidReocrd(this.id, record)
    	var index = this.datas.indexOf(record);    	
    	if(index == -1)return;
        this.datas.remove(record);
        if(count) this.totalCount --;
        this.selected.remove(record);
        //忘记这块代码的含义了.暂时去掉！
//        if(this.datas.length == 0){
//        	this.removeAll();
//        	return;
//        }
        var lindex = this.currentIndex - (this.currentPage-1)*this.psize;
        if(lindex<0)return;
        if(lindex<=this.datas.length){
        	this.locate(this.currentIndex,true);
        }else{
        	this.pre();
        }
        this.fireEvent("remove", this, record, index);
    },
    /**
     * 获取当前数据集下的所有数据.  
     * @return {Array} records 当前数据集的所有Record.
     */
    getAll : function(){
    	return this.datas;    	
    },
    /**
     * 查找数据.  
     * @param {String} property 查找的属性.
     * @param {Object} value 查找的属性的值.
     * @return {Spark.Record} 符合查找条件的第一个record
     */
    find : function(property, value){
    	var r = null;
    	this.each(function(record){
    		var v = record.get(property);
    		if(v ==value){
    			r = record;
    			return false;    			
    		}
    	}, this)
    	return r;
    },
    /**
     * 根据id查找数据.  
     * @param {String} id id.
     * @return {Spark.Record} 查找的record
     */
    findById : function(id){
    	var find = null,datas = this.backup||this.datas;
    	for(var i = 0,len = datas.length; i < len; i++){
            if(datas[i].id == id){
            	find = datas[i]
                break;
            }
        }
        return find;
    },
    /**
     * 删除所有数据.
     */
    removeAll : function(){
    	this.currentIndex = -1;
        this.totalCount = 0;
        this.datas = [];
        this.selected = [];
        this.fireEvent("clear", this);
    },
    /**
     * 返回指定record的位置
     * @return {Number} record所在的位置
     */
    indexOf : function(record){
        return this.datas.indexOf(record);
    },
    /**
     * 获取指定位置的record
     * @param {Number} 位置
     */
    getAt : function(index){
        return this.datas[index];
    },
    each : function(fn, scope){
        var items = [].concat(this.backup||this.datas); // each safe for removal
        for(var i = 0, len = items.length; i < len; i++){
            if(fn.call(scope || items[i], items[i], i, len) === false){
                break;
            }
        }
    },
    processCurrentRecord : function(){
    	var r = this.current();
    	for(var k in this.fields){
    		var field = this.fields[k];
    		if(field.type == 'dataset'){
    			var ds = field.pro['dataset'];
    			if(r && r.data[field.name]){
    				ds.reConfig(r.data[field.name]);
    			}else{
    				ds.clear();
    			}
    			ds.fireEvent('refresh',ds);
    			ds.processCurrentRecord();
    		}
    	}
    	if(r) this.fireEvent("indexchange", this, r);
    },
    /**
     * 获取所有选择的数据.
     * @return {Array} 所有选择数据.
     */
    getSelected : function(){
    	return this.selected;
    },
    /**
     * 选择所有数据.
     */
    selectAll : function(){
    	for(var i=0,l=this.datas.length;i<l;i++){
    		this.select(this.datas[i]);
    	}
    },
    /**
     * 取消所有选择.
     */
    unSelectAll : function(){
    	for(var i=0,l=this.datas.length;i<l;i++){
    		this.unSelect(this.datas[i]);
    	}
    },
    /**
     * 选择某个record.
     * @param {Spark.Record} record 需要选择的record.
     */
    select : function(r){
    	if(!this.sb)return;
    	if(typeof(r) == 'string'||typeof(r) == 'number') r = this.findById(r);
    	if(this.selected.indexOf(r) != -1)return;
        if(!this.execSelectFunction(r))return;
    	if(this.sb && this.sm == 'multiple'){
    		if(this.selected.indexOf(r) == -1) {
    			this.selected.push(r);
    			this.fireEvent('select', this, r);
    		}
       	}else{
       		if(this.selected.indexOf(r) == -1) {
	       		var or = this.selected[0];
	       		this.unSelect(or);
	       		this.selected = []
	       		this.selected.push(r);
	       		this.fireEvent('select', this, r);
       		}
       	}
    },
    execSelectFunction:function(r){
        if(this.sft){
            var selfun = $S.getFunction(this.sft);
            if(selfun == null){
                alert("未找到"+this.sft+"方法!")
            }else{
                var b=selfun.call(window,r);
                if(Ext.isDefined(b))return b;
            }
        }
        return true;
    },
    /**
     * 取消选择某个record.
     * @param {Spark.Record} record 需要取消选择的record.
     */
    unSelect : function(r){
        if(!this.sb)return;
        if(typeof(r) == 'string'||typeof(r) == 'number') r = this.findById(r);
    	if(this.sb){
    		if(this.selected.indexOf(r) != -1) {
    			this.selected.remove(r);
    			this.fireEvent('unselect', this, r);
    		}
    	}
    },
    /**
     * 定位到某个指针位置.
     * @param {Number} index 指针位置.
     */
    locate : function(index, force){
    	if(this.currentIndex == index && force !== true) return;
    	if(index <=0 || (index > this.totalCount + this.getNewRecrods().length))return;
    	var lindex = index - (this.currentPage-1)*this.psize;
    	if(this.datas[lindex - 1]){
	    	this.currentIndex = index;
    	}else{
    		if(this.isModified()){
    			$S.showInfoMessage('提示', '有未保存数据!')
    		}else{
				this.currentIndex = index;
				this.currentPage =  Math.ceil(index/this.psize);
				this.query(this.currentPage);
				return;
    		}
    	}
    	this.processCurrentRecord();
    },
    /**
     * 定位到某页.
     * @param {Number} page 页数.
     */
    page : function(page){
    	if(page >0) {
    		this.gotoPage = page;
            var go = (page-1)*this.psize + 1;
            var news = this.getAll().length-this.psize;
            if(this.currentPage < page && news > 0)go+=news;
//	    	var go = (page-1)*this.psize + this.getNewRecrods().length +1;
	    	this.locate(go);
    	}
    },
    /**
     * 定位到所有数据的第一条位置.
     */
    first : function(){
    	this.locate(1);
    },
    /**
     * 向前移动一个指针位置.
     */
    pre : function(){
    	this.locate(this.currentIndex-1);    	
    },
    /**
     * 向后移动一个指针位置.
     */
    next : function(){
    	this.locate(this.currentIndex+1);
    },
    /**
     * 定位到第一页.
     */
    firstPage : function(){
    	this.page(1);
    },
    /**
     * 刷新当前页
     */
    refresh : function(){
        this.query(this.currentPage);
    },
    /**
     * 向前移动一页.
     */
    prePage : function(){
    	this.page(this.currentPage -1);
    },
    /**
     * 向后移动一页.
     */
    nextPage : function(){
    	this.page(this.currentPage +1);
    },
    /**
     * 定位到最后一页.
     */
    lastPage : function(){
    	this.page(this.totalPage);
    },
    /**
     * 对当前数据集进行校验.
     * @return {Boolean} valid 校验结果.
     */
    validate : function(fire){
    	this.isValid = true;
    	var current = this.current();
    	var records = this.getAll();
		var dmap = {};
		var hassub = false;
		var ur = null;
					
    	for(var k in this.fields){
    		var field = this.fields[k];
    		if(field.type == 'dataset'){
    			hassub = true;
    			var d = field.pro['dataset'];
    			dmap[field.name] = d;
    		}
    	}
    	for(var k = 0,l=records.length;k<l;k++){
			var record = records[k];
			//有些项目是虚拟的字段,例如密码修改
//			if(record.isDirty == true || record.isNew == true) {
				if(!record.validate()){
					this.isValid = false;
					ur = record;
//					$S.addInValidReocrd(this.id, record);
				}else{
//					$S.removeInvalidReocrd(this.id, record);
				}
				if(this.isValid == false) {
					if(hassub)break;
				}else {
					for(var key in dmap){
						var ds = dmap[key];
						if(record.data[key]){
    						ds.reConfig(record.data[key]);
    						if(!ds.validate(false)) {
    							this.isValid = false;
    							ur = record;
    						}
    						ds.reConfig(current.data[key]);//循环校验完毕后,重新定位到当前行
						}
					}
					
					if(this.isValid == false) {
						break;
					}				
//				}
			}
		}
		
		if(ur != null){
			var r = this.indexOf(ur);
			if(r!=-1)this.locate(r+1);
		}
		if(fire !== false) {
			$S.EM.fireEvent('valid', $S.EM, this, this.isValid);
    		if(!this.isValid) $S.showInfoMessage('提示', '验证不通过!');  
		}
		//TODO: 希望能报出具体的校验信息,那个字段,什么原因.
		//TODO: 多语言.
		return this.isValid;
    },
    /**
     * 设置查询的Url.
     * @param {String} url 查询的Url.
     */
    setQueryUrl : function(url){
    	this.qurl = url;
    },
    /**
     * 设置查询的参数.
     * @param {String} para 参数名.
     * @param {Object} value 参数值.
     */
    setQueryParameter : function(para, value){
        this.qp[para] = value;
    },
    /**
     * 设置查询的DataSet.
     * @param {Spark.DataSet} ds DataSet.
     */
    setQueryDataSet : function(ds){ 
    	this.qds = ds;
    	if(this.qds.current() == null) this.qds.create();
    },
    /**
     * 设置提交的Url.
     * @param {String} url 提交的Url.
     */
    setSubmitUrl : function(url){
    	this.surl = url;
    },
    /**
     * 设置提交的参数.
     * @param {String} para 参数名.
     * @param {Object} value 参数值.
     */
    setSubmitParameter : function(para, value){
        this.sp[para] = value;
    },
    /**
     * 查询数据.
     * @param {Number} page(可选) 查询的页数.
     */
    query : function(page,opts){
        if(!this.qurl) return;
        if(this.qds) {
            if(this.qds.current() == null) this.qds.create();
            var sf=this,intervalId=setInterval(function(){
                if(!sf.qds.current().isReady)return;
                clearInterval(intervalId);
                if(!sf.qds.validate()) return;
                sf.doQuery(page,opts);
            },10);
        }else{
            this.doQuery(page,opts);
        }
    },
    
    doQuery : function(page,opts){
        var r;
        if(this.qds)r = this.qds.current();
    	if(!page) this.currentIndex = 1;
    	this.currentPage = page || 1;
    	
    	var q = {};
    	if(r != null) Ext.apply(q, r.data);
    	Ext.apply(q, this.qp);
    	for(var k in q){
    	   var v = q[k];
    	   if(Ext.isEmpty(v,false)) delete q[k];
    	}
    	var para = '_ps='+this.psize + '&_pn='+this.currentPage
    	var url = '';
    	if(this.qurl.indexOf('?') == -1){
    		url = this.qurl + '?' + para;
    	}else{
    		url = this.qurl + '&' + para;
    	}
        this.loading = true;
    	this.fireEvent("query", this);
        if(this.qtId) Ext.Ajax.abort(this.qtId);
    	this.qtId = $S.request({url:url, para:q, success:this.onLoadSuccess, error:this.onLoadError, scope:this,failure:this.onAjaxFailed,opts:opts});
    },
    /**
     * 判断当前数据集是否发生改变.
     * @return {Boolean} modified 是否发生改变.
     */
    isModified : function(){
    	var modified = false;
    	var records = this.getAll();
		for(var k = 0,l=records.length;k<l;k++){
			var record = records[k];
			if(record.isDirty == true || record.isNew == true) {
				modified = true;
				break;
			}else{
                for(var key in this.fields){
                    var field = this.fields[key];
                    if(field.type == 'dataset'){                
                        var ds = field.pro['dataset'];
                        ds.reConfig(record.data[field.name]);
                        if(ds.isModified()){
                            modified = true;
                            break;
                        }
                    }
                }
			}
		}
		return modified;
    },
    /**
     * 获取需要提交的数据.(编辑||新增)
     * @return {Object} 返回的对象.
     */
    getAllDatas : function(data){
    	var datas = [];
    	var items = data||this.datas;
//    	if(selected) items = this.getSelected();
    	for(var i=0,l=items.length;i<l;i++){
    		var r = items[i];
    		var isAdd = r.isDirty || r.isNew
			var d = Ext.apply({}, r.data);
			d['_id'] = r.id;
			d['_status'] = r.isNew ? 'insert' : 'update';
			for(var k in r.data){
				var item = d[k]; 
				if(item && item.xtype == 'dataset'){
					var ds = new $S.DataSet({});//$(item.id);
					ds.reConfig(item)
					isAdd = isAdd == false ? ds.isModified() :isAdd;
					d[k] = ds.getAllDatas();
				}
			}
    		if(isAdd||data){
	    		datas.push(d);    			
			}
    	}
    	return datas;
    },
    doSubmit : function(url, items, fields, success){
        //if(items.length==0)return; //会导致编辑界面直接点击保存无响应
        if(!this.validate()){           
            return;
        }
        this.surl = url||this.surl;
        if(this.surl == '') return;
        this.fireBindDataSetEvent("submit",url,items);
        this.lockComponent();
        var p = items;
        for(var i=0;i<p.length;i++){
            var data = p[i]
            //TODO:这里优化,对于更新的数据,只提交更新过的字段,没更新的不提交
            var r = this.findById(data['_id']);
            if(!r) continue;
            var dm = [];
            for(var key in data){
                var pst = true, f = this.fields[key];
                if(f) pst = f.getPro('persisted') !== true;
                if(fields && fields.indexOf(key)==-1 && key !='_id' && key != '_status'){
                    dm[dm.length] = key;
                } else if(!r.isNew && (r.modified == null || r.modified[key] === undefined) && pst && key !='_id' && key != '_status'){                    
                    dm[dm.length] = key;
                } 
//                else {
//                    data[key] = data[key]==='' ? null : data[key];
//                }
            }
            
            for(var j = 0;j<dm.length;j++){
                delete data[dm[j]];
            }
            
            //为什么改成null 可能是 aurora中为了方便处理...不太记得了.
//            for(var key in data){
//                var f = this.fields[key];
//                if(f && f.type != 'dataset' && data[key]==='')data[key]=null;
//            }
            p[i] = Ext.apply(p[i],this.sp)
        }
        $S.request({url:this.surl, para:p, success:success||this.onSubmitSuccess, error:this.onSubmitError, scope:this,failure:this.onAjaxFailed});
    },
    addLock: function(item){
        this.lock = this.lock || [];
        this.lock.concat([].concat(item));        
    },
    lockComponent : function(){
        if(this.loadingTip && Ext.get(this.loadingTip)) Ext.get(this.loadingTip).show();
        if(this.lock){
            for(var i=0;i<this.lock.length;i++){
                var cp = $(this.lock[i]);
                if(cp){
                    if(cp instanceof $S.Window) cp.closeable = false;
                    if(cp instanceof $S.Button) cp.disable();
                }
            }
        }
    },
    releaseComponent : function(){
        if(this.loadingTip && Ext.get(this.loadingTip)) Ext.get(this.loadingTip).setStyle('display','none');//hide();
        if(this.lock){
            for(var i=0;i<this.lock.length;i++){
                var cp = $(this.lock[i]);
                if(cp){
                    if(cp instanceof $S.Window) cp.closeable = true;
                    if(cp instanceof $S.Button) cp.enable();
                }
            }
        }
    },
    isAllReady:function(records){
        for(var i=0;i<records.length;i++){
            if(!records[i].isReady)return false;
        }
        return true;
    },
    /**
     * 提交选中数据.
     * @return {Object} cfg 提交参数.
     */
    submitSelected : function(cfg){
    	var sf=this;
        cfg = cfg||{};
    	var intervalId = setInterval(function(){
            var std = sf.getSelected();
            if(std.length == 0){
                $S.showInfoMessage('提示', '请选择一条数据!');
                clearInterval(intervalId);
                return;
            }
            if(!sf.isAllReady(std)) return;
            clearInterval(intervalId);
            if(sf.fireEvent("beforesubmit",sf)){
                var d = sf.getAllDatas(std);
                sf.doSubmit(cfg.url,d,cfg.fields);
            }
        },10);
    },
    /**
     * 提交数据.
     * @return {Object} cfg 提交参数.
     */
    submit : function(cfg){
        cfg = cfg||{};
    	var sf=this,data = cfg.data||sf.getAll(),intervalId=setInterval(function(){
            if(!sf.isAllReady(data))return;
            clearInterval(intervalId);
            if(sf.fireEvent("beforesubmit",sf)){
                var d = sf.getAllDatas(data);
                sf.doSubmit(cfg.url,[].concat(d),cfg.fields,cfg.success);
            }
        },10);
    },
    /**
     * 重置数据.
     * TODO:update数据的时候把原始数据放到oraValue字段中，reset的时候恢复
     * record上增加reset函数  ds上的循环调用record的reset
     * 触发事件？
     */
    reset : function(){
        var record=this.current();
        if(!record&&!record.fields)return;
        for(var c in record.fields){
            var v=record.fields[c].get('defaultValue');
            if(v!=record.get(c))
                record.set(c,v==undefined||v==null?"":v);
        }
    },
    fireBindDataSetEvent : function(event){
    	var a = Ext.toArray(arguments);
        var event = a[0];
        a[0] = this;
        this.fireEvent.apply(this,[event].concat(a))
        for(var k in this.fields){
            var field = this.fields[k];
            if(field.type == 'dataset'){  
                var ds = field.pro['dataset'];
                if(ds) {
                    ds.fireBindDataSetEvent(event)
                }
            }
        }
    },
    afterEdit : function(record, name, value) {
        this.fireEvent("update", this, record, name, value);
    },
    afterReject : function(record, name, value) {
    	this.fireEvent("reject", this, record, name, value);
    },
    commit : function(datas,fire) {
    	//this.clear();
    	for(var i=0,l=datas.length;i<l;i++){
    		var data = datas[i];
	    	var r = this.findById(data['_id']);
	    	if(r.isNew) this.totalCount ++;
	    	if(!r) return;
	    	r.commit();
	    	for(var k in data){
	    		var field = k;
				var f = this.fields[field];
				if(f && f.type == 'dataset'){
					var ds = f.pro['dataset'];
					ds.reConfig(r.data[f.name]);
	    			if(data[k].record) {
                        ds.commit([].concat(data[k].record), this.current() == r);                     
	    			}
				}else{
					var ov = r.get(field);
					var nv = data[k]
					if(field == '_id' || field == '_status') continue;
					if(f){
					   nv = this.processData(data,k,f);
					}
					if(ov != nv) {
						if(fire){
							//由于commit放到上面,这个时候不改变状态,防止重复提交
                            r.set(field,nv, true);
						}else{
                            r.data[field] = nv;
						}
					}
				}
	       	}
//	       	r.commit();//挪到上面了,record.set的时候会触发update事件,重新渲染.有可能去判断isNew的状态
    	}
    },
    //主要用来处理日期和时间类型,应为json没有日期格式
    processData: function(data, key,field){
        var v = data[key];
        if(v) {
            var dt = field.type;
            dt = dt ? dt.toLowerCase() : '';
            switch(dt){
                case 'date':
                    v = $S.dateFormat.parseDate(v,'isoDate');  
                    break;
                case 'datetime':
                    v = $S.dateFormat.parseDate(v,'isoDateTime');  
                    v.xtype = 'datetime';
                    break;
                case 'int':
                    v = parseInt(v);
                    break;
                case 'float':
                    v = parseFloat(v);
                    break;
                case 'boolean':
                    v = v.toLowerCase() =="true";
                    break;
            }
        }
        //TODO:判断key是否是valueField，然后设置displayField或者displayRenderer的值到对应的name上??
        return this.processValueListField(data,v,field);
    }, 
    processValueListField : function(data,v, field){
        var op = field.getPro('options'),df = field.getPro('displayField'),
            vf = field.getPro('valueField'),rf = field.getPro('returnField'),dr = field.getPro('displayRenderer'),rv = data[rf];
        if(rf && op && rv && !v){
            var options = $(op);
            if(options){
                var r = options.find(vf,rv);
                if(r){
                    var rder = $S.getFunction(dr);
                    if(rder){
                        v = rder.call(window,r);
                    }else{
                        v = r.get(df);
                    }
                }
            }            
        }
        return v;
    },
    onSubmitSuccess : function(res){
        var datas = []
        if(res.result){
            datas = [].concat(res.result);
            this.commit(datas,true)
        }
        this.releaseComponent();
        this.showSuccessTip();
        this.fireBindDataSetEvent('submitsuccess',res);
    },
    showSuccessTip : function(){
        var st = document.getElementById(this.successTip);
        if(st){
            Ext.fly(st).fadeIn();
            setTimeout(function(){
                Ext.fly(st).fadeOut();
            },1500);
        }
    },
    onLoadSuccess : function(res, options){
    	if(res == null) return;
    	if(!res.result) res.result = [];
    	var records = [].concat(res.result);
    	var total = res.total;
    	var datas = [];
    	if(records.length > 0){
    		for(var i=0,l=records.length;i<l;i++){
	    		var item = {
	    			data:records[i]	    		
	    		}
    			datas.push(item);
    		}
    	}else if(records.length == 0){
    		this.currentIndex  = 1
    	}
    	this.loadData(datas, total, options);
    	this.locate(this.currentIndex,true);
        this.loading = false;
    },
    onSubmitError : function(res){
        this.releaseComponent();
        this.fireBindDataSetEvent('submitfailed',res);
    },
    onAjaxFailed : function(res,opt){
        this.releaseComponent();
    	this.fireBindDataSetEvent('ajaxfailed',res,opt);
    },
    onLoadError : function(res,opt){
    	this.fireBindDataSetEvent('loadfailed', res,opt);
        this.loading = false;
    },
    onFieldChange : function(record,field,type,value) {
    	this.fireEvent('fieldchange', this, record, field, type, value)
    },
    onRecordValid : function(record, name, valid){
    	if(valid==false && this.isValid !== false) this.isValid = false;
    	this.fireEvent('valid', this, record, name, valid)
    }
});

/**
 * @class Spark.Record
 * <p>Record是一个数据对象.
 * @constructor
 * @param {Object} data 数据对象. 
 * @param {Array} fields 配置对象. 
 */
$S.Record = function(data){
	/**
     * Record的id. (只读).
     * @type Number
     * @property
     */
    this.id = ++$S.AUTO_ID;
    /**
     * Record的数据 (只读).
     * @type Object
     * @property
     */
    this.data = data;
    /**
     * Record的Fields (只读).
     * @type Object
     * @property
     */
    this.fields = {};
    /**
     * Record的验证信息 (只读).
     * @type Object
     * @property
     */
    this.valid = {};
    /**
     * Record的验证结果 (只读).
     * @type Boolean
     * @property
     */
    this.isValid = true; 
    /**
     * 是否是新数据 (只读).
     * @type Boolean
     * @property
     */
    this.isNew = false;
    /**
     * 是否发生改变 (只读).
     * @type Boolean
     * @property
     */
	this.isDirty = false;	
	/**
     * 编辑状态 (只读).
     * @type Boolean
     * @property
     */
	this.editing = false;
	/**
     * 编辑信息对象 (只读).
     * @type Object
     * @property
     */
	this.modified= null;
    /**
     * 是否是已就绪数据 (只读).
     * @type Boolean
     * @property
     */
    this.isReady=true;
};
$S.Record.prototype = {
	commit : function() {
		this.editing = false;
		this.valid = {};
		this.isValid = true;
		this.isNew = false;
		this.isDirty = false;
		this.modified = null;
	},
	/**
	 * 对当前record的所有field进行校验
	 * @return {boolean} isvalid 校验结果
	 */
	validate : function() {
		this.isValid = true;
		this.valid = {};
		var df = this.ds.fields;
		var rf = this.fields;
		var names = [];
		for(var k in df){
			if(df[k].type !='dataset')
			names.push(k);
		}
		
		for(var k in rf){
			if(names.indexOf(k) == -1){
				if(rf[k].type !='dataset')
				names.push(k);
			}
		}
		for(var i=0,l=names.length;i<l;i++){
			if(this.isValid == true) {
				this.isValid = this.validateField(names[i]);
			} else {
				this.validateField(names[i]);
			}
		}
		return this.isValid;
	},
	/**
	 * 对某个field进行校验.
	 * @param {String} name field的name
	 * @return {boolean} valid 校验结果
	 */
	validateField : function(name){
		var valid = true,v = this.get(name),field = this.getField(name),disabled = field.get('disabled');
        if(disabled == true) return valid;// 如果已经禁用就不需要校验
        
        var vv = v;
        if(v&&v.trim) vv = v.trim();
		if(Ext.isEmpty(vv) && field.get('required') == true){
			this.valid[name] = '当前字段不能为空!';
			valid =  false;
		}
        if(valid == true) {
            var restrict = field.get('restrict'),msg = field.get('validMessage'),validator = field.get('validator'),isvalid = true;
			if(validator){
				validator = window[validator];
				isvalid = validator.call(window,this, name, v);
				if(isvalid !== true){
					valid =	false;	
					this.valid[name] = isvalid;
				}
			}else if(restrict && !new RegExp(restrict).test(v)) {
                valid = false;  
                this.valid[name] = msg||'验证失败!';
            }
		}
		if(valid==true) delete this.valid[name];
		this.ds.onRecordValid(this,name,valid);
		return valid;
	},
    /**
     * 获取field
     * @param {String} name field的name
     * @return {Spark.Record.Field} field 
     */
    getField : function(name){
        if(!name)return null;
        var f = this.fields[name];
        var df = this.ds.fields[name];
        var rf;
        if(!f){
            if(df){
                f = new $S.Record.Field({name:df.name,type:df.type});
            }else{
                f = new $S.Record.Field({name:name});
            }
            f.record = this;
            this.fields[f.name]=f;
        }
  
        var pro = {};
        if(df) pro = Ext.apply(pro, df.pro);
        pro = Ext.apply(pro, f.pro);
        f.snap = pro;
        return f;
    },
    /**
     * 设置值.
     * @param {String} name 设定值的名字.
     * @param {Object} value 设定的值.
     * @param {Boolean} notDirty true 不改变record的isDirty状态.
     */
	set : function(name, value, notDirty){
        if(!$S.equals(this.data[name],value)) {
//        if(!(this.data[name] === value||(Ext.isDate(this.data[name])&&Ext.isDate(value)&&this.data[name].getTime()==value.getTime()))){
            if(!notDirty){
                this.isDirty = true;
                if(!this.modified){
                    this.modified = {};
                }
                if(typeof this.modified[name] == 'undefined'){
                    this.modified[name] = this.data[name] == undefined ? '' : this.data[name];
                }
            }
            this.data[name] = value;// == '' ? null : value; //考虑到mysql的因素,这里把空值转化成null.比较利于数据更新
            if(!this.editing && this.ds) {
                this.ds.afterEdit(this, name, value);
            }
        }
        this.validateField(name)
    },
    /**
     * 设置值.
     * @param {String} name 名字.
     * @return {Object} value 值.
     */
    get : function(name){
        return this.data[name];
    },
    reject : function(silent){
        var m = this.modified;
        for(var n in m){
            if(typeof m[n] != "function"){
                this.data[n] = m[n];
                this.ds.afterReject(this,n,m[n]);
            }
        }
        delete this.modified;
        this.editing = false;
        this.isDirty = false;
    },
    onFieldChange : function(fname, pname, value){
    	var field = this.getField(fname);
    	this.ds.onFieldChange(this, field, pname, value);
    }
}
/**
 * @class Spark.Record.Field
 * <p>Field是一个配置对象，主要配置指定列的一些附加属性，例如非空，只读，值列表等信息.
 * @constructor
 * @param {Object} data 数据对象. 
 */
$S.Record.Field = function(c){
    if(c.type) 
    this.type = c.type;
    this.name = c.name;
    this.pro = c||{};
    this.record;
};
$S.Record.Field.prototype = {
	setPro : function(name,value) {
		var op = this.pro[name];
		if(op !== value){
			this.pro[name] = value;
			if(this.record)this.record.onFieldChange(this.name, name, value);
		}
	},
	getPro : function(name){
		return this.pro[name]
	},
	/**
	 * 获取配置信息
	 * @param {String} name 配置名
	 * @return {Object} value 配置值
	 */
	get : function(name){
		var v = null;
		if(this.snap){
			v = this.snap[name];
		}
		return v;
	},
	/**
	 * 设置当前Field是否必输
	 * @param {Boolean} required  是否必输.
	 */
	setRequired : function(r){
		this.setPro('required',r);
        if(!r && this.record)this.record.validateField(this.name);
	},
	/**
	 * 当前Field是否必输.
	 * @return {Boolean} required  是否必输.
	 */
    isRequired : function(){
        return this.getPro('required');
    },
	/**
	 * 设置当前Field是否禁用.
	 * @param {Boolean} disabled 是否只读
	 */
	setDisabled : function(r){	
		this.setPro('disabled',r);
	},
	/**
	 * 当前Field是否只读.
	 * @return {Boolean} disabled 是否只读
	 */
	isDisabeld : function(){
        return this.getPro('disabled');
	},
	/**
	 * 设置当前Field的值列表.
	 * @param {Object} r 数据集
	 */
	setValueSet : function(v){
		this.setPro('valueset',v);
	},
	/**
     * 获取当前field对应的值列表.
     * @return {Object} r 数据集
     */
	getValueSet : function(){
		return this.getPro('valueset');
	},
	/**
     * 设置当前Field的映射.
     * 例如：<p>
       var mapping = [{from:'name', to: 'code'},{from:'service', to: 'name'}];</p>
       field.setMapping(mapping);
     * @return {Array} mapping 映射列表.
     * 
     */
	setMapping : function(m){
		this.setPro('mapping',m);
	},
	/**
     * 获取当前的映射.
     * @return {Array} array 映射集合
     */
	getMapping : function(){
        return this.getPro('mapping');
	},
	/**
     * 设置Lov弹出窗口的Title.
     * @param {String} title lov弹出窗口的Tile
     */
	setLovTitle : function(t){
		this.setPro('title',t);
	},
	/**
     * 设置Lov弹出窗口的宽度.
     * @param {Number} width lov弹出窗口的Width
     */
	setLovWidth : function(w){
        this.setPro('lovwidth',w);
	},
	/**
     * 设置Lov弹出窗口的高度.
     * @param {Number} height lov弹出窗口的Height
     */
	setLovHeight : function(h){
		this.setPro('lovheight',h);
	},
	/**
     * 设置Lov弹出窗口中grid的高度.
     * 配置这个主要是由于查询条件可能存在多个，导致查询的form过高.
     * @param {Number} height lov弹出窗口的grid组件的Height
     */
	setLovGridHeight : function(gh){
        this.setPro("lovgridheight",gh)
	},
//	/**
//     * 设置Lov的Model对象.
//     * Lov的配置可以通过三种方式.(1)model (2)service (3)url.
//     * @param {String} model lov配置的model.
//     */
//	setLovModel : function(m){
//        this.setPro("lovmodel",m) 
//	},
//	/**
//     * 设置Lov的Service对象.
//     * Lov的配置可以通过三种方式.(1)model (2)service (3)url.
//     * @param {String} service lov配置的service.
//     */
//	setLovService : function(m){
//        this.setPro("lovservice",m) 
//    },
//    /**
//     * 设置Lov的Url地址.
//     * Lov的配置可以通过三种方式.(1)model (2)service (3)url.
//     * 通过url打开的lov，可以不用调用setLovGridHeight
//     * @param {String} url lov打开的url.
//     */
//    setLovUrl : function(m){
//    	this.setPro("lovurl",m) 
//    },
    setLovPara : function(name,value){
        var p = this.getPro('lovpara');
        if(!p){
            p = {};
            this.setPro("lovpara",p) 
        }
        if(value==null){
        	delete p[name]
        }else{
            p[name] = value;
        }
    }
	
}